package com.atguigu.daijia.dispatch.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.fastjson.JSONObject;
import com.atguigu.daijia.common.constant.RedisConstant;
import com.atguigu.daijia.common.result.Result;
import com.atguigu.daijia.dispatch.mapper.OrderJobMapper;
import com.atguigu.daijia.dispatch.service.NewOrderService;
import com.atguigu.daijia.dispatch.xxl.client.XxlJobClient;
import com.atguigu.daijia.map.client.LocationFeignClient;
import com.atguigu.daijia.model.entity.dispatch.OrderJob;
import com.atguigu.daijia.model.enums.OrderStatus;
import com.atguigu.daijia.model.form.map.SearchNearByDriverForm;
import com.atguigu.daijia.model.vo.dispatch.NewOrderTaskVo;
import com.atguigu.daijia.model.vo.map.NearByDriverVo;
import com.atguigu.daijia.model.vo.order.NewOrderDataVo;
import com.atguigu.daijia.order.client.OrderInfoFeignClient;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

@Slf4j
@Service
@SuppressWarnings({"unchecked", "rawtypes"})
public class NewOrderServiceImpl implements NewOrderService {

    @Autowired
    private XxlJobClient xxlJobClient;

    @Autowired
    private OrderJobMapper orderJobMapper;

    @Autowired
    private LocationFeignClient locationFeignClient;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private OrderInfoFeignClient orderInfoFeignClient;


    //创建并启动任务调度方法
    @Override
    public Long addAndStartTask(NewOrderTaskVo newOrderTaskVo) {
        //判断当前订单是否启动任务调度
        LambdaQueryWrapper<OrderJob> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderJob::getOrderId,newOrderTaskVo.getOrderId());
        OrderJob orderJob = orderJobMapper.selectOne(queryWrapper);
        //若没有启动，进行操作
        if(orderJob == null){
            //创建并启动任务调度,jobJamdler为newOrderTaskHandler,无参数,每一分钟调用一次
            Long jobId = xxlJobClient.addAndStart("newOrderTaskHandler", "", "0 0/1 * * * ?", "新创建订单任务调度：" + newOrderTaskVo.getOrderId());
            //记录任务调度的信息
            orderJob = new OrderJob();
            orderJob.setOrderId(newOrderTaskVo.getOrderId());
            orderJob.setJobId(jobId);
            orderJob.setParameter(JSONObject.toJSONString(newOrderTaskVo));
            orderJobMapper.insert(orderJob);
        }
        //返回jobid
        return orderJob.getJobId();
    }

    //执行任务：搜索附近代驾司机
    @Override
    public void executeTask(long jobId) {
        //1.根据jobid查询数据库,当前任务是否已经创建
        //如果没有创建，就不往下执行了
        LambdaQueryWrapper<OrderJob> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(OrderJob::getJobId,jobId);
        OrderJob orderJob = orderJobMapper.selectOne(queryWrapper);
        if(orderJob == null){
            return;
        }
        //2.查询订单状态，如果当前订单状态为1(等待接单)，继续执行。如果当前订单不是1,停止任务调度
        //获取orderjob里的newOrderTaskVo对象
        String jsonStr = orderJob.getParameter();
        NewOrderTaskVo newOrderTaskVo = JSONObject.parseObject(jsonStr, NewOrderTaskVo.class);
        //获取orderId
        Long orderId = newOrderTaskVo.getOrderId();
        Result<Integer> orderStatusResult = orderInfoFeignClient.getOrderStatus(orderId);
        Integer status = orderStatusResult.getData();
        if(status.intValue() != OrderStatus.WAITING_ACCEPT.getStatus().intValue()){
            //停止任务调度
            xxlJobClient.stopJob(jobId);
            return;
        }
        //3.远程调用:查询附近满足条件的司机
        //封装参数
        SearchNearByDriverForm searchNearByDriverForm = new SearchNearByDriverForm();
        searchNearByDriverForm.setLongitude(newOrderTaskVo.getStartPointLongitude());
        searchNearByDriverForm.setLatitude(newOrderTaskVo.getStartPointLatitude());
        searchNearByDriverForm.setMileageDistance(newOrderTaskVo.getExpectDistance());
        //发起调用
        Result<List<NearByDriverVo>> result = locationFeignClient.searchNearByDriver(searchNearByDriverForm);
        //4.远程调用之后，获取满足可以接单的司机集合
        List<NearByDriverVo> nearByDriverVoList = result.getData();
        //5.遍历司机集合，得到每个司机，为每个司机创建临时队列,存储新的订单信息
        nearByDriverVoList.forEach(driver -> {
            //使用Redis的Set(保证不重复),记录能接收到该订单的司机id,防止重复推送
            //根据订单id生成key
            String repeatKey = RedisConstant.DRIVER_ORDER_REPEAT_LIST + newOrderTaskVo.getOrderId();
            //判断该司机是否接收到该订单
            Boolean isMember = stringRedisTemplate.opsForSet().isMember(repeatKey,driver.getDriverId().toString());
            if(!isMember){
                //把订单推送给满足条件的多个司机
                stringRedisTemplate.opsForSet().add(repeatKey,driver.getDriverId().toString());
                //过期时间：15min,超过15分钟没有接单自动取消
                stringRedisTemplate.expire(repeatKey,15, TimeUnit.MINUTES);
                NewOrderDataVo newOrderDataVo = BeanUtil.copyProperties(newOrderTaskVo, NewOrderDataVo.class);
                newOrderDataVo.setDistance(driver.getDistance());
                //将新订单存入司机的临时队列中，用Redis的List来实现
                String key = RedisConstant.DRIVER_ORDER_TEMP_LIST + driver.getDriverId();
                stringRedisTemplate.opsForList().leftPush(key,JSONObject.toJSONString(newOrderDataVo));
                //设置过期时间为1min
                stringRedisTemplate.expire(key,1,TimeUnit.MINUTES);
            }

        });

    }

    //从临时队列中查询司机新订单数据
    @Override
    public List<NewOrderDataVo> findNewOrderQueueData(Long driverId) {
        List<NewOrderDataVo> list = new ArrayList<>();
        String key = RedisConstant.DRIVER_ORDER_TEMP_LIST + driverId;
        Long size = stringRedisTemplate.opsForList().size(key);
        if(size>0){
            for(int i=0;i<size;i++){
                //优先取最新的,所以是leftpop,相当于栈
                String content = stringRedisTemplate.opsForList().leftPop(key);
                NewOrderDataVo newOrderDataVo = JSONObject.parseObject(content, NewOrderDataVo.class);
                list.add(newOrderDataVo);
            }
        }
        return list;
    }

    //清空新订单队列数据
    @Override
    public Boolean clearNewOrderQueueData(Long driverId) {
        String key = RedisConstant.DRIVER_ORDER_TEMP_LIST + driverId;
        Boolean isDelete = stringRedisTemplate.delete(key);
        return isDelete;
    }
}
